"""
服务器/客户端:
    文件处理:
        查看,上传,下载,退出
    网络:
        socket tcp
    多线程
        thread
"""

from socket import *
from threading import Thread
from multiprocessing import Process
import sys
import os
import time


# 全局常量
ADDR = ("0.0.0.0", 18693)
FTP = "/root/FTP/"

# 创建类,实现服务器文件处理功能


class FTPFileServer:
    """
    查看列表,下载,上传,退出处理
    """
    pass


# 多线程模型
class FTPServer(Thread):
    """
    网络服务, 多线程
    """

    def __init__(self, *args):
        super().__init__()
        self.__connfd = args

    def run(self):
        self.start_(self.__connfd[0], self.__connfd[1])

    def start_(self, *args):
        c = args[0]  # 消息
        d = args[1]  # 地址
        while True:
            data = c.recv(1024).decode()  # 收取消息

            # 判读类型
            if not data or data == 'Q':
                print("有客户端退出了", d)
                return
            elif data == 'L':
                self.__do_list(c)
            elif data[0] == 'G':
                filename = data.split(' ', 1)[-1]
                self.__do_get(filename, c)
            elif data == 'P':
                filename = data.split(' ', 1)[-1]
                self.__do_put(filename, c)

            print(f"客户端: {d}发送的消息: {data}")

        c.close()

    def __do_put(self, name, c):
        if os.path.exists(FTP + name):
            c.send("文件以存在,请重新发送.".encode())
            return
        else:
            c.send(b'ok')
            time.sleep(0.1)

        f = open(FTP + name, 'wb')
        while True:
            date = c.recv(1024)
            if date == b'##':
                break
            f.write(date)
        f.close()

    def __do_get(self, name, c):
        try:
            f = open(FTP+name, 'rb')
        except Exception:
            c.send("打开失败,文件不存在".encode())
            return
        else:
            c.send('ok'.encode())
            time.sleep(0.1)  # 卡一下时间,防止沾包

        while True:
            data = f.read(1024)
            if not data:
                time.sleep(0.1)  # 卡一下时间,防止沾包
                c.send(b"##")
                break
            c.send(data)

    def __do_list(self, c):
        """获取文件列表"""
        files = os.listdir(FTP)
        if not files:
            c.send("文件夹为空.".encode())
            return
        else:
            # 拼接字符串
            files_ = ""
            for item in files:
                # 如果不想发送隐藏和文件夹则添加这行代码
                if item[0] != '.' and os.path.isfile(FTP+item):
                    files_ += item + "\n"  # 列表中每个元素添加换行符作为切割使用
            c.send(f"ok {files_}".encode())
            # print(files_)


# 搭建网络服务模型
class Main:
    def __init__(self):
        self.__sockfd = socket()
        self.__sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.__sockfd.bind(ADDR)
        self.__sockfd.listen(5)

        self.__start_()

    def __start_(self):
        while True:
            print("等待连接...")

            try:
                connfd, addr = self.__sockfd.accept()
                print("有客户端连接:", addr)
            except KeyboardInterrupt:
                print("检测到客户端非正常退出!")
                sys.exit()
            except Exception as e:
                print("遇到了一个错误:", e)
                continue

            so = FTPServer(connfd, addr)
            so.setDaemon = True
            so.start()


# 测试
if __name__ == "__main__":
    main = Main()
